package com.lagou.edu.factory;

import com.alibaba.druid.util.StringUtils;
import com.lagou.edu.annotation.Autowired;
import com.lagou.edu.annotation.Service;
import com.lagou.edu.annotation.Transactional;
import org.reflections.Reflections;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author 应癫
 * <p>
 * 工厂类，生产对象（使用反射技术）
 */
public class BeanFactory {

	/**
	 * 任务一：读取解析xml，通过反射技术实例化对象并且存储待用（map集合）
	 * 任务二：对外提供获取实例对象的接口（根据id获取）
	 */

	// 存储对象
	private static Map<String, Object> map = new HashMap<>();

	static {
		try {
			//1、扫描全包
			Reflections reflections = new Reflections("com.lagou.edu");
			Set<Class<?>> serviceAnnotatedClassList = reflections.getTypesAnnotatedWith(Service.class);
			//2、扫描有Service注解的地方
			findServiceAnnotated(serviceAnnotatedClassList);
			//2、扫描其中Autowired注解的地方，有则传入对应的值
			for (String key : map.keySet()) {
				setAutowiredValue(key);
			}
			//3、扫描其中Transactional注解的地方，有则实现事务
			setTransactional();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}
	}

	private static void findServiceAnnotated(Set<Class<?>> serviceAnnotatedClassList) throws
			InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
		for (Class<?> serviceClass : serviceAnnotatedClassList) {
			//获取Service注释
			Service serviceClassAnnotation = serviceClass.getAnnotation(Service.class);
			if (serviceClassAnnotation != null) {
				//获取bean的Id，若存在则使用自定义名称
				String value = serviceClassAnnotation.value();
				if (StringUtils.isEmpty(value)) {
					//当前是否实现接口，若有则使用接口名
					Class<?>[] interfaces = serviceClass.getInterfaces();
					if (interfaces != null && interfaces.length > 0) {
						//接口名称
						value = interfaces[0].getName();
					} else {
						//处理为首字母小写的类名
						value = serviceClass.getTypeName();//toLowerCaseFirstOne(serviceClass.getSimpleName());
					}
				}
				//通过反射实例化对象
				Object o = serviceClass.getDeclaredConstructor().newInstance();
				//存储内容
				map.put(value, o);
			}
		}
	}

	private static void setAutowiredValue(String key) throws IllegalAccessException {
		//获取service类
		Object service = map.get(key);
		//反射获取对应的内容
		Field[] fields = service.getClass().getDeclaredFields();
		for (Field field : fields) {
			Autowired annotation = field.getAnnotation(Autowired.class);
			if (annotation != null) {
				String typeName = field.getType().getName();
				Object bean = map.get(typeName);
				// if (bean == null) {
				// 	bean = map.get(field.getType().getName());
				// }
				if (bean != null) {
					field.setAccessible(true);
					field.set(service, bean);
				}
			}
		}
	}

	public static void setTransactional() {
		for (String key : map.keySet()) {
			//获取service类
			Object service = map.get(key);
			Class<?> serviceClass = service.getClass();
			Transactional annotation = serviceClass.getAnnotation(Transactional.class);
			if (annotation != null) {
				ProxyFactory proxyFactory = (ProxyFactory) map.get(ProxyFactory.class.getTypeName());
				//实现接口的代理类，使用jdk
				if (serviceClass.getInterfaces() != null && serviceClass.getInterfaces().length > 0) {
					service = proxyFactory.getJdkProxy(service);
				} else {
					service = proxyFactory.getCglibProxy(service);
				}
				map.put(key, service);
			}
		}
	}

	public static String toLowerCaseFirstOne(String s) {
		if (Character.isLowerCase(s.charAt(0))) {
			return s;
		} else {
			return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
		}
	}

	/**
	 * 任务二：对外提供获取实例对象的接口（根据id获取）
	 *
	 * @param id
	 * @return
	 */
	public static Object getBean(String id) {
		return map.get(id);
	}
}
